﻿namespace PowerSong.Import
    {
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;
    using PowerSong.SongDatabase;

    public class OpenLyricsImport : BaseImport
        {

        private string sourceFolderLocation = null;

        public OpenLyricsImport(Database destinationDatabase, string sourceFolderLocation)
            : base(destinationDatabase)
            {
            this.sourceFolderLocation = sourceFolderLocation;
            }

        protected override void Import(Category category, List<string> messages)
            {

            const string NewLineTag = "<br />";
            const string TemporaryNewLineTag = "{NewLine}";

            // Ensure the source folder exists
            if (!Directory.Exists(sourceFolderLocation))
                {
                throw new Exception("The folder '" + sourceFolderLocation + "' does not exist.");
                }

            // Perform the import
            foreach (var fileName in Directory.GetFiles(sourceFolderLocation))
                {

                // Preprocess the file
                var text = File.ReadAllText(fileName).Replace(NewLineTag, TemporaryNewLineTag);
                using (var textReader = new StringReader(text))
                    {

                    // Get the songs contained in the document
                    XNamespace ns = "http://openlyrics.info/namespace/2009/song";
                    var document = XDocument.Load(textReader);
                    var songs = from XElement song
                                in document.Descendants(ns + "song")
                                select new
                                    {
                                    Properties = song.Element(ns + "properties"),
                                    Lyrics = song.Element(ns + "lyrics")
                                    };

                    // Write out each of the songs
                    foreach (var song in songs)
                        {
                        var songToWrite = new Song();
                        songToWrite.Categories.Add(category);

                        // Extract properties
                        var songProperties = new
                            {
                            Titles = song.Properties.Element(ns + "titles"),
                            Copyright = song.Properties.Element(ns + "copyright"),
                            Authors = song.Properties.Element(ns + "authors")
                            };

                        // Set title
                        songToWrite.Title = songProperties.Titles == null || songProperties.Titles.Element(ns + "title") == null
                            ? "Untitled Song"
                            : songProperties.Titles.Element(ns + "title").Value ?? "Untitled Song";

                        // Set copyright
                        songToWrite.Copyright = songProperties.Copyright == null || songProperties.Copyright == null
                            ? string.Empty
                            : songProperties.Copyright.Value;

                        // Set authors
                        songToWrite.Authors.Clear();
                        if (songProperties.Authors != null && songProperties.Authors.Element(ns + "author") != null)
                            {

                            // Get the authors defined in the file
                            var authors = from XElement element
                                          in songProperties.Authors.Descendants(ns + "author")
                                          select element.Value;

                            // Add the authors to the song
                            songToWrite.Authors.AddRange(authors);

                            }

                        // Set verses
                        songToWrite.Verses.Clear();
                        if (song.Lyrics != null &&
                            song.Lyrics.Element(ns + "verse") != null &&
                            song.Lyrics.Element(ns + "verse").Element(ns + "lines") != null)
                            {

                            // Get and process each of the verses
                            var verses = from XElement element
                                         in song.Lyrics.Descendants(ns + "verse")
                                         select element;
                            foreach (var verse in verses)
                                {

                                // Add the next verse
                                if (verse.Descendants(ns + "lines") != null)
                                    {
                                    var linesNode = verse.Element(ns + "lines");
                                    if (linesNode.Value != null)
                                        {
                                        songToWrite.Verses.Add(linesNode.Value.Replace(TemporaryNewLineTag, Environment.NewLine));
                                        }
                                    }

                                // Check whether or not there are multiple verses
                                if (verse.Descendants(ns + "lines").Count() > 1)
                                    {
                                    messages.Add("The song contained in file '" + fileName + "' has alternative verses. Only the first set of verses have been imported for this song.");
                                    }

                                }

                            }

                        // Perform some checks with the song to ensure we can write it
                        var errorMessage = string.Empty;
                        if (string.IsNullOrWhiteSpace(songToWrite.Title))
                            {
                            errorMessage = "The song contained in file '" + fileName + "' has no title therefore it cannot be imported.";
                            }
                        if (songToWrite.Verses.Count == 0)
                            {
                            errorMessage = "The song contained in file '" + fileName + "' has no verses therefore it cannot be imported.";
                            }

                        // Add the song if possible
                        if (errorMessage == string.Empty)
                            {
                            Destination.Songs.Write(songToWrite);
                            }
                        else
                            {
                            messages.Add(errorMessage);
                            }

                        }

                    }

                }

            }

        }

    }
